#pragma once
#include "util.hpp"
#include <mutex>
#include <assert.h>
class user_table
{
public:
    user_table(const std::string &host,
               const std::string &username,
               const std::string &passwd,
               const std::string &dbname,
               uint16_t port = 3306)
    {
        DEBUG_LOG("mysql初始化");
        _mysql = mysql_util::mysql_create(host, username, passwd, dbname, port);
        assert(_mysql != nullptr);
    }
    ~user_table()
    {
        DEBUG_LOG("mysql退出");
        mysql_util::mysql_destory(_mysql);
        _mysql = nullptr;
    }
    // 注册新增
    bool insert(Json::Value &user)
    {
#define INSERT_USER "insert user values(null,'%s',SHA2('%s',256),1000,0,0)"
        Json::Value val;
        if(user["username"].isNull()||user["password"].isNull())
        {
            DEBUG_LOG("请输入用户名或者密码");
            return false;
        }
        if (select_by_name(user["username"].asString(), val) == true)
        {
            INFO_LOG("该用户%s已存在\n", user["username"].asCString());
            return false;
        }
        char sql[4096] = {0};
        sprintf(sql, INSERT_USER, user["username"].asCString(), user["password"].asCString());
        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if (ret == false)
        {
            ERROR_LOG("执行注册sql语句失败\n");
            return false;
        }
        DEBUG_LOG("插入用户:%s成功\n",user["username"].asCString());
        return true;
    }
    // 登录
    bool login(Json::Value &user)
    {
// 以用户名和密码一同作为验证条件
#define LOGIN_USER "select id,score,total_count,win_count from user where username='%s' and password=SHA2('%s',256)"
        char sql[4096] = {0};
        sprintf(sql, LOGIN_USER, user["username"].asCString(), user["password"].asCString());
        MYSQL_RES *res = nullptr;
        {
            std::unique_lock<std::mutex> guard(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if (ret == false)
            {
                ERROR_LOG("执行登录sql语句失败\n");
                return false;
            }
            res = mysql_store_result(_mysql);
        }
        //只有执行语句失败，结果集才会是空指针，否则正常返回的结果集可以是一个值为空的结果集（搜索到的就是0条数据）
        int row_num = mysql_num_rows(res);
        if (row_num == 0)
        {
            DEBUG_LOG("没有用户:%s 数据\n", user["username"].asCString());
            return false;
        }
        if (row_num > 1)
        {
            DEBUG_LOG("找到多条用户数据:%s\n", user["username"].asCString());
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = std::stoi(row[0]);
        user["score"] = std::stoi(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        DEBUG_LOG("登录用户:%s成功\n",user["username"].asCString());
        return true;
    }
    bool select_by_name(const std::string &name, Json::Value &user)
    {
#define USER_BY_NAME "select id,score,total_count,win_count from user where username='%s'"
        char sql[4096] = {0};
        sprintf(sql, USER_BY_NAME, name.c_str());
        MYSQL_RES *res = nullptr;
        {
            std::unique_lock<std::mutex> guard(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if (ret == false)
            {
                ERROR_LOG("通过名字获取用户失败\n");
                return false;
            }
            res = mysql_store_result(_mysql);
        }
        int row_num = mysql_num_rows(res);
        if (row_num == 0)
        {
            DEBUG_LOG("没有用户:%s 数据\n", name.c_str());
            return false;
        }
        if (row_num > 1)
        {
            DEBUG_LOG("找到多条用户数据:%s\n,%d", name.c_str(),row_num);
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = std::stoi(row[0]);
        user["username"] = name;
        user["score"] = std::stoi(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        
        mysql_free_result(res);
        return true;
    }
    bool select_by_id(int id, Json::Value &user)
    {
#define USER_BY_ID "select username,score,total_count,win_count from user where id=%d"
        char sql[4096] = {0};
        sprintf(sql, USER_BY_ID, id);
        MYSQL_RES *res = nullptr;
        {
            std::unique_lock<std::mutex> guard(_mutex);
            bool ret = mysql_util::mysql_exec(_mysql, sql);
            if (ret == false)
            {
                ERROR_LOG("通过id获取用户失败\n");
                return false;
            }
            res = mysql_store_result(_mysql);
        }
        int row_num = mysql_num_rows(res);
        if (row_num == 0)
        {
            DEBUG_LOG("没有用户:%d 数据\n", id);
            return false;
        }
        
        if (row_num > 1)
        {
            DEBUG_LOG("找到多条用户%d数据\n", id);
            return false;
        }
        MYSQL_ROW row = mysql_fetch_row(res);
        user["id"] = id;
        user["username"] = row[0];
        user["score"] = std::stoi(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);
        mysql_free_result(res);
        return true;
    }
    bool win(uint64_t id)
    {
#define USER_WIN "update user set score=score+30,total_count=total_count+1,win_count=win_count+1 where id=%ld"
        char sql[4096] = {0};
        sprintf(sql, USER_WIN, id);
        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if (ret == false)
        {
            ERROR_LOG("修改胜利用户数据失败\n");
            return false;
        }
        //DEBUG_LOG("执行加分操作");
        return true;
    }
    bool lose(uint64_t id)
    {
#define USER_LOSE "update user set score=score-30,total_count=total_count+1 where id=%ld"
        char sql[4096] = {0};
        sprintf(sql, USER_LOSE, id);
        bool ret = mysql_util::mysql_exec(_mysql, sql);
        if (ret == false)
        {
            ERROR_LOG("修改失败用户数据失败\n");
            return false;
        }
        return true;
    }

private:
    MYSQL *_mysql;
    std::mutex _mutex;
};